#!/usr/bin/perl
#
# Jun 1, 2010 Deives Michellis <dmichellis@uolinc.com>
#

use Getopt::Std;
use POSIX;
use strict;

my %options = ();


sub HELP_MESSAGE {
	print "Uso: ".$0." [OPCOES]... -- comando 

 -s tempo_de_sleep       # sleep
 -t tempo_para_timeout   # timeout
 -d                      # debug
";
	exit(0);
}

sub VERSION_MESSAGE {

}
getopts('hds:t:', \%options);

my $cmd = shift @ARGV;

HELP_MESSAGE() if defined($options{h}) or !defined($cmd);

print STDERR "> Executando comando $cmd \"".join(" ", @ARGV)."\"".(defined($options{s}) ? " com delay entre 0 e ".$options{s}."s" : "").(defined($options{t}) ? " em no maximo ".$options{t}."s" : "").".\n" if defined($options{d});

#
# Faz o sleep (caso necessario)
#
if (defined($options{s})) {
	my $sleep=(int(rand($options{s})));
	print STDERR "> Aguardando $sleep segundos para rodar o comando\n" if defined($options{d});
	sleep($sleep);
	print STDERR "> Fim do sleep\n" if defined($options{d});
}


my $mask = POSIX::SigSet->new( SIGALRM );
my $action = POSIX::SigAction->new( sub { die "timeout na execucao" },$mask,);
sigaction( SIGALRM, $action);

my ($ret);
# Autoflush
$| = 1;
if (my $pid = fork() ) {
	# parent
	eval { 
		alarm($options{t}) if (defined($options{t}) && $options{t} > 0);
		# Aguarda o child acabar e pega o exit status
		my $child = waitpid($pid, 0);
		$ret = WEXITSTATUS($?);
		alarm(0);
	};
	if ($@) {
		#
		# Ja deu timeout; faz soft-kill com sigterm
		#
		print STDERR "> Timeout em $cmd. Mandando SIGTERM\n" if defined($options{d});
		kill "TERM", $pid;
		eval {
			# Espera alguns segundos pelo TERM e manda o KILL caso nao tenha encerrado
			alarm(10);
			waitpid($pid, 0);
			alarm(0);
		};
		if ($@) {
			print STDERR "> Processo $cmd nao respondeu ao SIGTERM. Enviando SIGKILL\n" if defined($options{d});
			kill "KILL", $pid;
		}
		$ret = 255;
	}
	exit($ret);
} else {
	exec $cmd, @ARGV;
	#
	# Este bloco so eh executado quando o exec nao roda
	#
	print STDERR "$cmd: $!\n";
	exit(255);
}

